#include "Hal.h"
#include "userSys.h"

/*tools for meter modBus*/

static uint8_t g_mRecvBuff[128];
static uint8_t g_modbusRecvCount = 0;

float intTofloat(int i)
{
	union {
		int i;
		float f;
	} c;
	c.i = i;
	if(c.f == -0)
	{
		return 0.0;
	}
	return c.f;
}

unsigned int crc16(unsigned char *buf, unsigned char length)
{  
  unsigned char i;  
  unsigned int crc=0xFFFF;
  
  while(length--)  
    for(crc^=*(buf++),i=0;i<8;i++)  
      crc=(crc&0x0001)?(crc>>1)^0xA001:crc>>1;  
  return crc;  
}

int exchangeValue(uint8_t *val, uint8_t isNomal)
{
    int32_t value = 0;
    if(isNomal)
    {
        value |= val[0] << 24;
        value |= val[1] << 16;
        value |= val[2] << 8;
        value |= val[3];
    }
    else
    {
        value |= val[0] << 8;
        value |= val[1];
        value |= val[2] << 24;
        value |= val[3] << 16;
    }
	
    return value;
}

void ModbusCtrlInit(GPIO_TypeDef* port, uint16_t pin)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Pin = pin;
    GPIO_Init(port, &GPIO_InitStructure);

	GPIO_ResetBits(port, pin);
}

void ModbusCtrlSetMode(GPIO_TypeDef* port, uint16_t pin,uint8_t tx)
{
	if(tx)
	{
		GPIO_SetBits(port, pin);
	}
	else
	{
		GPIO_ResetBits(port, pin);
	}
}

void modbusReadRegs(HalUart_t uart ,uint8_t devAddr, uint8_t cmd, uint16_t startReg, uint16_t length)
{
    uint8_t readCmd[8], i = 0;
    uint16_t crc;

    readCmd[i++] = devAddr;
    readCmd[i++] = cmd; //read cmd
    readCmd[i++] = (uint8_t)(startReg >> 8);
    readCmd[i++] = (uint8_t)(startReg & 0x00ff);
    readCmd[i++] = (uint8_t)(length >> 8);
    readCmd[i++] = (uint8_t)(length & 0x00ff);
    crc = crc16(readCmd, i);
    readCmd[i++] = (uint8_t)(crc & 0x00ff);
    readCmd[i++] = (uint8_t)(crc >> 8);

	SysDataPrint(readCmd, i);
	HalUartWrite(uart, readCmd, i);
}

void modbusWriteRegs(HalUart_t uart ,uint8_t devAddr, uint8_t cmd, uint16_t startReg, uint16_t regNum, uint8_t length, uint32_t data)
{
    uint8_t writeCmd[13] = {0};
    uint8_t i = 0;
    uint16_t crc;

    writeCmd[i++] = devAddr;
    writeCmd[i++] = cmd; //read cmd
    writeCmd[i++] = (uint8_t)(startReg >> 8);
    writeCmd[i++] = (uint8_t)(startReg & 0x00ff);
    writeCmd[i++] = (uint8_t)(regNum >> 8);
    writeCmd[i++] = (uint8_t)(regNum & 0x00ff);
    writeCmd[i++] = length;
    if(length == 2)
    {
        writeCmd[i++] = data >> 8 & 0xff;
        writeCmd[i++] = data & 0xff;
    }
    else if(length == 4)
    {
        writeCmd[i++] = data >> 24 & 0xff;
        writeCmd[i++] = data >> 16 & 0xff;
        writeCmd[i++] = data >> 8  & 0xff;
        writeCmd[i++] = data & 0xff;
    }
    
    crc = crc16(writeCmd, i);
    writeCmd[i++] = (uint8_t)(crc & 0x00ff);
    writeCmd[i++] = (uint8_t)(crc >> 8);

	SysDataPrint(writeCmd, i);
	HalUartWrite(uart, writeCmd, i);

}


//TODO work on only one uart, fix it!
void modbusRecvHandle(uint8_t byte, uint8_t procode, ModBusRecvCallback_t recvCallBack)
{
    static uint8_t dataLen;
    uint16_t crc;

    g_mRecvBuff[g_modbusRecvCount++] = byte;
    
    if(g_modbusRecvCount >= sizeof(g_mRecvBuff))
    {
        g_modbusRecvCount = 0;
    }

    if(g_modbusRecvCount == 1)
    {
        if(byte != procode)
        {
            g_modbusRecvCount = 0;
        }
    }
    else if(g_modbusRecvCount == 3)
    {
        dataLen = byte;
    }
    else if(g_modbusRecvCount == dataLen + 5)
    {
#if 1
        uint8_t i;
        SysLog("");
        for(i = 0; i < g_modbusRecvCount; i++)
        {
            SysPrintf("%02x ", g_mRecvBuff[i]);
        }
        SysPrintf("\n");
#endif
        crc = byte;
        crc = (crc << 8) + g_mRecvBuff[g_modbusRecvCount - 2];
        if(crc == crc16(g_mRecvBuff, g_modbusRecvCount - 2))
        {
            recvCallBack((ModbusReplyProtcol_t *)g_mRecvBuff);
        }
        else
        {
            SysLog("crc16 error!");
        }
        memset(g_mRecvBuff, 0, sizeof(g_mRecvBuff));
        g_modbusRecvCount = 0;
        dataLen = 0;
    }
}

